import customtkinter as ctk
from tkinter import filedialog, messagebox
import subprocess
import threading
import os
import re

# --- 主应用窗口定义 ---
class VideoConverterApp(ctk.CTk):
    def __init__(self):
        super().__init__()

        # --- 窗口基础设置 ---
        self.title("Modern Video Converter (for Web)")
        self.geometry("800x650")
        ctk.set_appearance_mode("System")  # 支持 Light/Dark 模式
        ctk.set_default_color_theme("blue")
        
        self.grid_columnconfigure(0, weight=1)
        self.grid_rowconfigure(3, weight=1)

        # --- 变量定义 ---
        self.input_file_path = ctk.StringVar()
        self.output_file_path = ctk.StringVar()
        self.quality_var = ctk.IntVar(value=23)
        self.preset_var = ctk.StringVar(value="medium")
        self.resolution_var = ctk.StringVar()

        # --- UI 组件创建 ---
        self.create_widgets()

    def create_widgets(self):
        # --- Frame 1: 文件选择 ---
        file_frame = ctk.CTkFrame(self)
        file_frame.grid(row=0, column=0, padx=20, pady=20, sticky="ew")
        file_frame.grid_columnconfigure(1, weight=1)

        ctk.CTkLabel(file_frame, text="Input File:").grid(row=0, column=0, padx=10, pady=10, sticky="w")
        self.input_entry = ctk.CTkEntry(file_frame, textvariable=self.input_file_path, state="readonly")
        self.input_entry.grid(row=0, column=1, padx=10, pady=10, sticky="ew")
        ctk.CTkButton(file_frame, text="Browse...", command=self.browse_input_file).grid(row=0, column=2, padx=10, pady=10)

        ctk.CTkLabel(file_frame, text="Output File:").grid(row=1, column=0, padx=10, pady=10, sticky="w")
        self.output_entry = ctk.CTkEntry(file_frame, textvariable=self.output_file_path, state="readonly")
        self.output_entry.grid(row=1, column=1, padx=10, pady=10, sticky="ew")
        ctk.CTkButton(file_frame, text="Save As...", command=self.browse_output_file).grid(row=1, column=2, padx=10, pady=10)

        # --- Frame 2: 转换设置 ---
        settings_frame = ctk.CTkFrame(self)
        settings_frame.grid(row=1, column=0, padx=20, pady=0, sticky="ew")
        settings_frame.grid_columnconfigure((0, 1, 2), weight=1)

        # Quality (CRF)
        quality_frame = ctk.CTkFrame(settings_frame, fg_color="transparent")
        quality_frame.grid(row=0, column=0, padx=10, pady=10, sticky="ew")
        ctk.CTkLabel(quality_frame, text=f"Quality (CRF): {self.quality_var.get()}").grid(row=0, column=0)
        ctk.CTkSlider(quality_frame, from_=18, to=28, number_of_steps=10, variable=self.quality_var, command=self.update_quality_label).grid(row=1, column=0, sticky="ew")
        
        # Preset
        preset_frame = ctk.CTkFrame(settings_frame, fg_color="transparent")
        preset_frame.grid(row=0, column=1, padx=10, pady=10, sticky="ew")
        ctk.CTkLabel(preset_frame, text="Encoding Speed:").grid(row=0, column=0)
        preset_options = ['ultrafast', 'superfast', 'veryfast', 'faster', 'fast', 'medium', 'slow', 'slower', 'veryslow']
        ctk.CTkOptionMenu(preset_frame, variable=self.preset_var, values=preset_options).grid(row=1, column=0, sticky="ew")
        
        # Resolution
        res_frame = ctk.CTkFrame(settings_frame, fg_color="transparent")
        res_frame.grid(row=0, column=2, padx=10, pady=10, sticky="ew")
        ctk.CTkLabel(res_frame, text="Resolution (e.g., 1280 or 1920:1080):").grid(row=0, column=0)
        ctk.CTkEntry(res_frame, textvariable=self.resolution_var, placeholder_text="Keep Original").grid(row=1, column=0, sticky="ew")

        # --- Frame 3: 执行按钮 ---
        action_frame = ctk.CTkFrame(self)
        action_frame.grid(row=2, column=0, padx=20, pady=20, sticky="ew")
        self.convert_button = ctk.CTkButton(action_frame, text="Start Conversion", font=("Arial", 16), command=self.start_conversion_thread)
        self.convert_button.pack(expand=True, fill="both", ipady=10)
        
        # --- Frame 4: 日志输出 ---
        log_frame = ctk.CTkFrame(self)
        log_frame.grid(row=3, column=0, padx=20, pady=0, sticky="nsew")
        log_frame.grid_rowconfigure(0, weight=1)
        log_frame.grid_columnconfigure(0, weight=1)
        self.log_textbox = ctk.CTkTextbox(log_frame, state="disabled", font=("Courier New", 12))
        self.log_textbox.grid(row=0, column=0, sticky="nsew")
        
    def update_quality_label(self, value):
        # 更新质量滑块旁的标签
        label = self.winfo_children()[1].winfo_children()[0].winfo_children()[0]
        label.configure(text=f"Quality (CRF): {int(value)}")

    def browse_input_file(self):
        # 弹出文件选择对话框
        file_path = filedialog.askopenfilename(
            title="Select a Video File",
            filetypes=(("Video Files", "*.mp4 *.mov *.avi *.mkv *.webm"), ("All files", "*.*"))
        )
        if file_path:
            self.input_file_path.set(file_path)
            # 自动生成建议的输出文件名
            path, ext = os.path.splitext(file_path)
            self.output_file_path.set(f"{path}_converted.mp4")

    def browse_output_file(self):
        # 弹出文件保存对话框
        file_path = filedialog.asksaveasfilename(
            title="Save Converted File As",
            defaultextension=".mp4",
            filetypes=(("MP4 files", "*.mp4"), ("All files", "*.*"))
        )
        if file_path:
            self.output_file_path.set(file_path)

    def log(self, message):
        # 在GUI的日志文本框中安全地添加消息
        self.log_textbox.configure(state="normal")
        self.log_textbox.insert("end", message + "\n")
        self.log_textbox.see("end")
        self.log_textbox.configure(state="disabled")

    def start_conversion_thread(self):
        # 使用线程来运行转换，避免GUI卡死
        input_path = self.input_file_path.get()
        output_path = self.output_file_path.get()

        if not input_path or not output_path:
            messagebox.showerror("Error", "Please select both input and output files.")
            return

        # 禁用按钮，防止重复点击
        self.convert_button.configure(state="disabled", text="Converting...")
        self.log_textbox.configure(state="normal")
        self.log_textbox.delete("1.0", "end")
        self.log_textbox.configure(state="disabled")

        # 创建并启动转换线程
        thread = threading.Thread(
            target=self.run_ffmpeg_conversion,
            args=(input_path, output_path)
        )
        thread.daemon = True
        thread.start()

    def run_ffmpeg_conversion(self, input_path, output_path):
        try:
            # 从GUI获取参数
            crf = self.quality_var.get()
            preset = self.preset_var.get()
            resolution = self.resolution_var.get()
            
            self.log("🚀 Starting FFmpeg conversion...\n")
            
            # 构建FFmpeg命令
            command = [
                'ffmpeg', '-i', input_path, '-c:v', 'libx264',
                '-crf', str(crf), '-preset', preset, '-c:a', 'aac',
                '-pix_fmt', 'yuv420p', '-movflags', '+faststart', '-y'
            ]
            
            if resolution:
                res_string = f"scale={''.join(filter(str.isdigit, resolution))}:-2" if ':' not in resolution else f"scale={resolution}"
                command.extend(['-vf', res_string])

            command.append(output_path)
            
            self.log("FFmpeg command:")
            self.log(' '.join(f'"{arg}"' if ' ' in arg else arg for arg in command) + "\n")

            # 执行FFmpeg
            process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True, encoding='utf-8')

            # 实时读取并显示输出
            for line in process.stdout:
                self.after(0, self.log, line.strip())

            process.wait()

            # 转换完成后的处理
            if process.returncode == 0:
                self.after(0, self.conversion_finished, True)
            else:
                self.after(0, self.conversion_finished, False, "Conversion failed. Check logs for details.")
                
        except FileNotFoundError:
            self.after(0, self.conversion_finished, False, "Error: 'ffmpeg' not found. Please ensure it's installed and in your system's PATH.")
        except Exception as e:
            self.after(0, self.conversion_finished, False, f"An unexpected error occurred: {str(e)}")

    def conversion_finished(self, success, message=None):
        # 在主线程中更新UI
        self.convert_button.configure(state="normal", text="Start Conversion")
        if success:
            self.log("\n" + "="*30)
            self.log("🎉 Conversion Successful!")
            self.log("="*30)
            messagebox.showinfo("Success", "Video conversion completed successfully!")
        else:
            self.log("\n" + "!"*30)
            self.log(f"❌ {message}")
            self.log("!"*30)
            messagebox.showerror("Error", message)

# --- 程序入口 ---
if __name__ == "__main__":
    app = VideoConverterApp()
    app.mainloop()